snapshot: Change how gtk_snapshot_push/pop works
authorBenjamin Otte <otte@redhat.com>
Tue, 13 Dec 2016 01:33:15 +0000 (02:33 +0100)
committerBenjamin Otte <otte@redhat.com>
Tue, 20 Dec 2016 17:01:10 +0000 (18:01 +0100)
Instead of appending a container node and adding the nodes to it as they
come in, we now collect the nodes until gtk_snapshot_pop() is called and
then hand them out in a container node.

The caller of gtk_snapshot_push() is then responsible for doing whatever
he wants with the created node.

Another addigion is the keep_coordinates flag to gtk_snapshot_push()
which allows callers to keep the current offset and clip region or
discard it. Discarding is useful when doing transforms, keeping it is
useful when inserting effect nodes (like the ones I'm about to add).

docs/reference/gsk/gsk4-sections.txt
gsk/gskrendernode.h
gsk/gskrendernodeimpl.c
gtk/gtkrendericon.c
gtk/gtksnapshot.c
gtk/gtksnapshot.h
gtk/gtksnapshotprivate.h

index 102d08467c8f87a3b4ccce901e31af771e4a8dbe..4bbeba513a4759834693baeb734fbf67a0a7f32a 100644 (file)
@@ -38,7 +38,6 @@ gsk_texture_node_new
 gsk_cairo_node_new
 gsk_cairo_node_get_draw_context
 gsk_container_node_new
-gsk_container_node_append_child
 gsk_container_node_get_n_children
 gsk_container_node_get_child
 gsk_transform_node_new
index b98bd56ce637f121478361af09b724a2ba6102ed..93a100eaf64bc94f9d1a9cc8041c73249adb9c0e 100644 (file)
@@ -55,15 +55,13 @@ cairo_t *               gsk_cairo_node_get_draw_context         (GskRenderNode
                                                                  GskRenderer              *renderer);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_container_node_new                  (void);
+GskRenderNode *         gsk_container_node_new                  (GskRenderNode           **children,
+                                                                 guint                     n_children);
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_container_node_append_child         (GskRenderNode           *node,
-                                                                 GskRenderNode           *child);
+guint                   gsk_container_node_get_n_children       (GskRenderNode            *node);
 GDK_AVAILABLE_IN_3_90
-guint                   gsk_container_node_get_n_children       (GskRenderNode           *node);
-GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_container_node_get_child            (GskRenderNode           *node,
-                                                                 guint                    idx);
+GskRenderNode *         gsk_container_node_get_child            (GskRenderNode            *node,
+                                                                 guint                     idx);
 
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_transform_node_new                  (GskRenderNode            *child,
index e719a1d6e954d5b87d170268b80aa60fc20da3d4..d23d18ddbac5d60f2e272f3773466034b048a026 100644 (file)
@@ -285,15 +285,20 @@ struct _GskContainerNode
 {
   GskRenderNode render_node;
 
-  GPtrArray *children;
+  GskRenderNode **children;
+  guint n_children;
 };
 
 static void
 gsk_container_node_finalize (GskRenderNode *node)
 {
   GskContainerNode *container = (GskContainerNode *) node;
+  guint i;
+
+  for (i = 0; i < container->n_children; i++)
+    gsk_render_node_unref (container->children[i]);
 
-  g_ptr_array_unref (container->children);
+  g_free (container->children);
 }
 
 static void
@@ -302,9 +307,9 @@ gsk_container_node_make_immutable (GskRenderNode *node)
   GskContainerNode *container = (GskContainerNode *) node;
   guint i;
 
-  for (i = 1; i < container->children->len; i++)
+  for (i = 1; i < container->n_children; i++)
     {
-      gsk_render_node_make_immutable (g_ptr_array_index (container->children, i));
+      gsk_render_node_make_immutable (container->children[i]);
     }
 }
 
@@ -343,53 +348,32 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
 
 /**
  * gsk_container_node_new:
+ * @children: (array length=n_children) (transfer none): The children of the node
+ * @n_children: Number of children in the @children array
  *
- * Creates a new #GskRenderNode instance for holding multiple different
- * render nodes. You can use gsk_container_node_append_child() to add
- * nodes to the container.
+ * Creates a new #GskRenderNode instance for holding the given @children.
+ * The new node will acquire a reference to each of the children.
  *
  * Returns: (transfer full): the new #GskRenderNode
  *
  * Since: 3.90
  */
 GskRenderNode *
-gsk_container_node_new (void)
+gsk_container_node_new (GskRenderNode **children,
+                        guint           n_children)
 {
   GskContainerNode *container;
+  guint i;
 
   container = (GskContainerNode *) gsk_render_node_new (&GSK_CONTAINER_NODE_CLASS);
 
-  container->children = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
+  container->children = g_memdup (children, sizeof (GskRenderNode *) * n_children);
+  container->n_children = n_children;
 
-  return &container->render_node;
-}
+  for (i = 0; i < container->n_children; i++)
+    gsk_render_node_ref (container->children[i]);
 
-/**
- * gsk_container_node_append_child:
- * @node: a container node
- * @child: a #GskRenderNode
- *
- * Appends @child to the list of children of @node.
- *
- * This function acquires a reference on @child.
- *
- * Returns: (transfer none): the #GskRenderNode
- *
- * Since: 3.90
- */
-GskRenderNode *
-gsk_container_node_append_child (GskRenderNode *node,
-                                 GskRenderNode *child)
-{
-  GskContainerNode *container = (GskContainerNode *) node;
-
-  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), NULL);
-  g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node);
-  g_return_val_if_fail (node->is_mutable, node);
-
-  g_ptr_array_add (container->children, gsk_render_node_ref (child));
-
-  return node;
+  return &container->render_node;
 }
 
 /**
@@ -409,7 +393,7 @@ gsk_container_node_get_n_children (GskRenderNode *node)
 
   g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), 0);
 
-  return container->children->len;
+  return container->n_children;
 }
 
 GskRenderNode *
@@ -419,9 +403,9 @@ gsk_container_node_get_child (GskRenderNode *node,
   GskContainerNode *container = (GskContainerNode *) node;
 
   g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), NULL);
-  g_return_val_if_fail (idx < container->children->len, 0);
+  g_return_val_if_fail (idx < container->n_children, 0);
 
-  return g_ptr_array_index (container->children, idx);
+  return container->children[idx];
 }
 
 /*** GSK_TRANSFORM_NODE ***/
index 0304f0d02f2b8754114ca2ad2c772b92584e7537..082f87d7d2702a14bbcb26685839bb6cfa9ec681 100644 (file)
@@ -126,7 +126,7 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
   else
     {
       graphene_matrix_t m1, m2, m3;
-      GskRenderNode *transform_node, *container_node;
+      GskRenderNode *transform_node, *icon_node;
       double offset_x, offset_y;
 
       gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
@@ -136,15 +136,16 @@ gtk_css_style_snapshot_icon (GtkCssStyle            *style,
       graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
       graphene_matrix_multiply (&m2, &m3, &m1);
 
-      container_node = gsk_container_node_new ();
-      gsk_render_node_set_name (container_node, "CSS Icon Transform Container");
-      transform_node = gsk_transform_node_new (container_node, &m1);
+      gtk_snapshot_push (snapshot, FALSE, "CSS Icon Transform Container");
+      gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
+      icon_node = gtk_snapshot_pop (snapshot);
+
+      transform_node = gsk_transform_node_new (icon_node, &m1);
       gsk_render_node_set_name (transform_node, "CSS Icon Transform");
       gtk_snapshot_append_node (snapshot, transform_node);
       
-      gtk_snapshot_push_node (snapshot, container_node);
-      gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
-      gtk_snapshot_pop (snapshot);
+      gsk_render_node_unref (transform_node);
+      gsk_render_node_unref (icon_node);
     }
 }
 
index 331e9804d33c845dbc357dc1ad8a8298d5fb18d5..ff0eda2dd7a1de8a77c2421471ee1e1deb6f641b 100644 (file)
 
 static GtkSnapshotState *
 gtk_snapshot_state_new (GtkSnapshotState *parent,
+                        char             *name,
                         cairo_region_t   *clip,
-                        GskRenderNode    *node)
+                        double            translate_x,
+                        double            translate_y)
 {
   GtkSnapshotState *state;
 
   state = g_slice_new0 (GtkSnapshotState);
 
-  state->node = node;
+  state->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
+
   state->parent = parent;
+  state->name = name;
+  state->translate_x = translate_x;
+  state->translate_y = translate_y;
   if (clip)
     state->clip_region = cairo_region_reference (clip);
 
@@ -68,9 +74,13 @@ gtk_snapshot_state_new (GtkSnapshotState *parent,
 static void
 gtk_snapshot_state_free (GtkSnapshotState *state)
 {
+  g_ptr_array_unref (state->nodes);
+
   if (state->clip_region)
     cairo_region_destroy (state->clip_region);
 
+  g_free (state->name);
+
   g_slice_free (GtkSnapshotState, state);
 }
 
@@ -81,66 +91,49 @@ gtk_snapshot_init (GtkSnapshot          *snapshot,
                    const char           *name,
                    ...)
 {
-  cairo_rectangle_int_t extents;
-
-  cairo_region_get_extents (clip, &extents);
+  char *str;
 
   snapshot->state = NULL;
   snapshot->renderer = renderer;
-  snapshot->root = gsk_container_node_new ();
 
   if (name)
     {
       va_list args;
-      char *str;
 
       va_start (args, name);
       str = g_strdup_vprintf (name, args);
       va_end (args);
-
-      gsk_render_node_set_name (snapshot->root, str);
-
-      g_free (str);
     }
+  else
+    str = NULL;
 
-  snapshot->state = gtk_snapshot_state_new (NULL, (cairo_region_t *) clip, snapshot->root);
+  snapshot->state = gtk_snapshot_state_new (NULL,
+                                            str,
+                                            (cairo_region_t *) clip,
+                                            0, 0);
 }
 
 GskRenderNode *
 gtk_snapshot_finish (GtkSnapshot *snapshot)
 {
-  gtk_snapshot_pop (snapshot);
+  GskRenderNode *result;
+  
+  result = gtk_snapshot_pop (snapshot);
 
   if (snapshot->state != NULL)
     {
       g_warning ("Too many gtk_snapshot_push() calls.");
     }
 
-  return snapshot->root;
-}
-
-/**
- * gtk_snapshot_push_node:
- * @snapshot: a #GtkSnapshot
- * @node: the render node to push
- *
- * Makes @node the new current render node. You are responsible for adding
- * @node to the snapshot.
- *
- * Since: 3.90
- */
-void
-gtk_snapshot_push_node (GtkSnapshot   *snapshot,
-                        GskRenderNode *node)
-{
-  g_return_if_fail (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE);
-
-  snapshot->state = gtk_snapshot_state_new (snapshot->state, snapshot->state->clip_region, node);
+  return result;
 }
 
 /**
  * gtk_snapshot_push:
  * @snapshot: a #GtkSnapshot
+ * @keep_coordinates: If %TRUE, the current offset and clip will be kept.
+ *     Otherwise, the clip will be unset and the offset will be reset to
+ *     (0, 0).
  * @bounds: the bounds for the new node
  * @name: (transfer none): a printf() style format string for the name for the new node
  * @...: arguments to insert into the format string
@@ -152,30 +145,38 @@ gtk_snapshot_push_node (GtkSnapshot   *snapshot,
  */
 void
 gtk_snapshot_push (GtkSnapshot           *snapshot,
+                   gboolean               keep_coordinates,
                    const char            *name,
                    ...)
 {
-  GskRenderNode *node;
-
-  node = gsk_container_node_new ();
+  char *str;
 
   if (name)
     {
       va_list args;
-      char *str;
 
       va_start (args, name);
       str = g_strdup_vprintf (name, args);
       va_end (args);
-
-      gsk_render_node_set_name (node, str);
-
-      g_free (str);
     }
+  else
+    str = NULL;
 
-  gtk_snapshot_append_node (snapshot, node);
-  gtk_snapshot_push_node (snapshot, node);
-  gsk_render_node_unref (node);
+  if (keep_coordinates)
+    {
+      snapshot->state = gtk_snapshot_state_new (snapshot->state,
+                                                str,
+                                                snapshot->state->clip_region,
+                                                snapshot->state->translate_x,
+                                                snapshot->state->translate_y);
+    }
+  else
+    {
+      snapshot->state = gtk_snapshot_state_new (snapshot->state,
+                                                str,
+                                                NULL,
+                                                0, 0);
+    }
 }
 
 /**
@@ -185,23 +186,45 @@ gtk_snapshot_push (GtkSnapshot           *snapshot,
  * Removes the top element from the stack of render nodes,
  * making the node underneath the current node again.
  *
+ * Returns: (transfer full) (allow none): A #GskRenderNode for
+ *     the contents that were rendered to @snapshot since
+ *     the corresponding gtk_snapshot_push() call
+ *
  * Since: 3.90
  */
-void
+GskRenderNode *
 gtk_snapshot_pop (GtkSnapshot *snapshot)
 {
   GtkSnapshotState *state;
+  GskRenderNode *node;
 
   if (snapshot->state == NULL)
     {
       g_warning ("Too many gtk_snapshot_pop() calls.");
-      return;
+      return NULL;
     }
 
   state = snapshot->state;
   snapshot->state = state->parent;
 
+  if (state->nodes->len == 0)
+    {
+      node = NULL;
+    }
+  else if (state->nodes->len == 1)
+    {
+      node = gsk_render_node_ref (g_ptr_array_index (state->nodes, 0));
+    }
+  else
+    {
+      node = gsk_container_node_new ((GskRenderNode **) state->nodes->pdata,
+                                     state->nodes->len);
+      gsk_render_node_set_name (node, state->name);
+    }
+
   gtk_snapshot_state_free (state);
+
+  return node;
 }
 
 /**
@@ -288,7 +311,7 @@ gtk_snapshot_append_node (GtkSnapshot   *snapshot,
 
   if (snapshot->state)
     {
-      gsk_container_node_append_child (snapshot->state->node, node);
+      g_ptr_array_add (snapshot->state->nodes, gsk_render_node_ref (node));
     }
   else
     {
index 6acb5aa50a869bd74fdf3da1f589b739370fbdaf..2c6253340021faf0026619aaf4035a8250fe638c 100644 (file)
@@ -41,13 +41,11 @@ GskRenderer *   gtk_snapshot_get_renderer               (const GtkSnapshot
 
 GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_push                       (GtkSnapshot            *snapshot,
+                                                         gboolean                keep_coordinates,
                                                          const char             *name,
-                                                         ...) G_GNUC_PRINTF(2, 3);
+                                                         ...) G_GNUC_PRINTF (3, 4);
 GDK_AVAILABLE_IN_3_90
-void            gtk_snapshot_push_node                  (GtkSnapshot            *snapshot,
-                                                         GskRenderNode          *node);
-GDK_AVAILABLE_IN_3_90
-void            gtk_snapshot_pop                        (GtkSnapshot            *snapshot);
+GskRenderNode * gtk_snapshot_pop                        (GtkSnapshot            *snapshot) G_GNUC_WARN_UNUSED_RESULT;
 
 GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_translate_2d               (GtkSnapshot            *snapshot,
index 54b3a6bbbec1660c719c96ac7efbce127f0bd976..eb8cbacba0206a0dc76a78138de92e7fc645a83f 100644 (file)
@@ -27,7 +27,8 @@ typedef struct _GtkSnapshotState GtkSnapshotState;
 struct _GtkSnapshotState {
   GtkSnapshotState      *parent;
 
-  GskRenderNode         *node;
+  char                  *name;
+  GPtrArray             *nodes;
 
   cairo_region_t        *clip_region;
   double                 translate_x;
@@ -37,7 +38,6 @@ struct _GtkSnapshotState {
 struct _GtkSnapshot {
   GtkSnapshotState      *state;
 
-  GskRenderNode         *root;
   GskRenderer           *renderer;
 };